/*
*	Project: Aethon
*
*	File: Scene.cpp
*
*	Author: Caleb Reinking
*
*	Date: 2/15/2009
*
*   Purpose: The scene is supposed to be  a messenger boy for the Director
*            class. The director gives high level commands to the Scene, then
*            the Scene passes on those low level commands and implementation
*            to the Terrain, Model, and PhysicsManager classes
*            Scene Class Implementation File
*/

#include "../include/Scene.h"
#include "../include/Control.h"
#include "../include/Eye.h"
#include "../include/vector3f.h"
#include "../include/ModelPart.h"

#include <iostream>
#include <fstream>

using namespace std;
	
bool wireFrameDesired = false;

void initEye();
void update(PhysicsManager *physMan, vector<Model> *modelListPtr, Terrain *terrainPtr);
void generateNewPosition(Model& modelA);

	
//-------------------------------------------------------------------------	
//------------------- Methods ---------------------------------------------
//##########################################################################
int Scene::startTime()
{
   cout << "int Scene::startTime()" << endl;
   cout << "Starts counting the world time - an unpause" << endl << endl;
   return this->worldTime;
} // end startTime
	
//##########################################################################
int Scene::updateTime()
{
   cout << "int Scene::updateTime()" << endl;
   cout << "Not sure about the usage or purpose of this function." 
		<< endl << endl;
	return this->worldTime;
} // end updateTime

//##########################################################################
void Scene::toggleNextControl()
{
   Control *theControl = Control::getInstanceOf();
   Model *oldCamera = theControl->getModelPtr();
   currentModIndex = (currentModIndex+1)%modelList.size();  
   Model *camera = &modelList.at(currentModIndex);   
   theControl->setModelPtr(camera);
   oldCamera->setHasVisibility(true);
   camera->setHasVisibility(false);
   Eye myeye = camera->getEye();
   myeye.update(camera->getPosition(),camera->getDirection());
   myeye.setIsActive(true);
   camera->setEye(myeye);
   
} // end toggleNextControl

//##########################################################################
void Scene::togglePreviousControl()
{
   Control *theControl = Control::getInstanceOf();
   Model *oldCamera = theControl->getModelPtr();
   currentModIndex = (currentModIndex+modelList.size()-1)%modelList.size();  
   Model *camera = &modelList.at(currentModIndex);   
   theControl->setModelPtr(camera);
   oldCamera->setHasVisibility(true);
   camera->setHasVisibility(false);
   Eye myeye = camera->getEye();
   myeye.update(camera->getPosition(),camera->getDirection());
   myeye.setIsActive(true);
   camera->setEye(myeye);
   
} // end toggleNextControl

//##########################################################################
void Scene::toggleCollisions()
{
   physMan.setHasCollisions(!physMan.getHasCollisions());
   cout<<"collisions: "<<physMan.getHasCollisions()<<endl;
} // end toggleNextControl

//##########################################################################
void Scene::toggleNextEye()
{
   cout << "void Scene::toggleNextEye()" << endl;
   cout << "Not sure about this implementation and dependence on other classes"
        << endl << endl;
} // end toggleNextEye
	
void Scene::load()
{
   Control *myControl = Control::getInstanceOf();
     
   //create test model for control to adjust  
   //set control pointer as camera
     
   terrain = Terrain();
   terrain.load( "heightmapWithIsland", "texture3flip" );
   
   ifstream modelListFile;
   modelListFile.open( "../data/models/Aethon_1_0.mll" );
   
   string modelName;
   
   modelListFile >> modelName;
   while( modelListFile )
   {
      insertModelIntoList( modelName );
      modelListFile >> modelName;
   }
   
    myControl->setModelPtr(&modelList[0]);//set control pointer as camera
    initEye();

   modelListFile.close();
   
}

//##########################################################################
void Scene::insertModelIntoList( string modelName )
{
    Model tempModel;
    tempModel.load( modelName );
 //   if(modelName == "tilion"){
 //   for(int i=0; i<50; i++){tempModel.pushMovement("tilion_walk");}
 //   }
    modelList.push_back( tempModel );
}
	
//##########################################################################
void Scene::display( int windowHeight, int windowWidth )
{
   //cout << "void Scene::display()" << endl;
   //cout << "Draws the scene to the screen using other class display methods" 
   //     << endl << endl;
   Timer *myTimer = Timer::getInstanceOf();
   
   glMatrixMode(GL_MODELVIEW);

   glLoadIdentity();

   if (wireFrameDesired)
      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
   else
      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   
   update(&physMan,getModListPtr(), getTerrainPtr());

   terrain.display();
   for( int i = 0 ; i < (int)modelList.size() ; i++ )
   {
        modelList[i].display();
   }
   
   glPushMatrix();
   glDisable(GL_DEPTH_TEST);
   glDepthMask(GL_FALSE);
   viewOrtho(windowHeight, windowWidth);
   
   glEnable (GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); 
	//glColor3f(0.0f,1.0f,0.0f);
   
   glColor3ub( 200, 200, 200 );
   glBegin( GL_QUADS );
	   glVertex2f(windowWidth*0.25, windowHeight*0.9);
	   glVertex2f(windowWidth*0.25, windowHeight*0.95);
	   glVertex2f(windowWidth*0.25+windowWidth*0.5*myTimer->getRatioTimeLeft(), windowHeight*0.95);
	   glVertex2f(windowWidth*0.25+windowWidth*0.5*myTimer->getRatioTimeLeft(), windowHeight*0.90);
   glEnd();
   
   glColor3ub( (int)(255*modelList[currentModIndex].getPosition().v[1]/27.0),
              255-(int)(255*modelList[currentModIndex].getPosition().v[1]/27.0),
              255-(int)(255*modelList[currentModIndex].getPosition().v[1]/27.0) );
   glBegin( GL_QUADS );
       //TODO: replce 25.0 with a maximum height found on the map. Currently seg faults if I try
	   glVertex2f(windowWidth*0.90, 
                  windowHeight*0.75-windowHeight*0.5*modelList[currentModIndex].getPosition().v[1]/27.0  );
	   glVertex2f(windowWidth*0.90, windowHeight*0.75);
	   glVertex2f(windowWidth*0.95, windowHeight*0.75);
	   glVertex2f(windowWidth*0.95, 
                  windowHeight*0.75-windowHeight*0.5*modelList[currentModIndex].getPosition().v[1]/27.0 );
   glEnd();
   
    glDisable (GL_BLEND);


     
   
   viewPerspective();
   glEnable(GL_DEPTH_TEST);
   glDepthMask(GL_TRUE);
   
   glPopMatrix();

} // end display

void Scene::viewOrtho(int x, int y)
{
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	glOrtho( 0, x , y , 0, -1, 1 );
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();
}

void Scene::viewPerspective(void)
{
	glMatrixMode( GL_PROJECTION );
	glPopMatrix();
	glMatrixMode( GL_MODELVIEW );
	glPopMatrix();
}

//#############################################################
// FINAL DESTINGATION: scene? supposedly camera model that would have all those values.
void initEye()
{
	Control *myControl = Control::getInstanceOf();
	Model *camera = myControl->getModelPtr();
	
	//set direction to look where we want using internal degrees
	vector3f dir(0,45/9.11,0);
	camera->setDirection(dir);
	camera->setHasVisibility(false);
	
	Eye myeye = camera->getEye();
	myeye.update(camera->getPosition(),camera->getDirection());
	myeye.setIsActive(true);
	camera->setEye(myeye);
	
}//end function



//######################################################
void update(PhysicsManager *physMan, vector<Model> *modelListPtr, Terrain *terrainPtr)
{
   Control *myControl = Control::getInstanceOf();  
   Model *cameraPtr = myControl->getModelPtr();
   //cout << "entered update in scene.cpp" << endl;
   myControl->updateVelocity();
   //myControl->updateDirection();

   //generateNewPosition(*cameraPtr);
   physMan->update(modelListPtr, terrainPtr);
   Eye myeye = cameraPtr->getEye();
   myeye.update(cameraPtr->getPosition(),cameraPtr->getDirection());
   cameraPtr->setEye(myeye);
   //cout << "leaving update in scene.cpp" << endl;
}

//######################################################
void generateNewPosition(Model& modelA)
{//for now it just sets position, ignoring collisions so that we can move the camera
	vector3f tempVel = modelA.getVelocity();
	vector3f tempPos = modelA.getPosition();

	tempPos.v[0] += tempVel.v[0];
	tempPos.v[1] += tempVel.v[1];
	tempPos.v[2] += tempVel.v[2];
	
	modelA.setPosition(tempPos);
	vector3f zeroVect(0,0,0);
	modelA.setVelocity(zeroVect);
}//end gennewPosition
